﻿Imports Microsoft.DirectX
Imports Microsoft.DirectX.Direct3D
Imports Microsoft.DirectX.DirectPlay
Imports Commander_Wars.Spieletools
Imports System.Net.Sockets
''' <summary>
''' Informationen über die Netzwerkteilnehmer
''' </summary>
''' <remarks></remarks>
Public Class MemberInfo
    Public ID As Integer 'the ID assigned to this used (by the server)
    Public Flags As MemberFlag
    Public Username As String
    Public Sub New(ByVal ID As Integer)
        Me.ID = ID
        Flags = MemberFlag.Lobby
    End Sub
    Public Sub New(ByVal ID As Integer, ByVal Bereit As MemberFlag)
        Me.ID = ID
        Me.Flags = Flags
    End Sub
    Public Sub New(ByVal ID As Integer, ByVal Name As String)
        Me.ID = ID
        Me.Username = Name
        Flags = MemberFlag.Lobby
    End Sub
    Public Sub New(ByVal ID As Integer, ByVal Name As String, ByVal Bereit As MemberFlag)
        Me.ID = ID
        Me.Username = Name
        Me.Flags = Bereit
    End Sub
    Public Sub New()
        Flags = MemberFlag.Lobby
        Username = My.Settings.Autor
        ID = BaseLobby.FindNewMemberID
    End Sub
    Enum MemberFlag
        Lobby = 1
        Joined = 2
        InGame = 4
    End Enum
    
End Class
''' <summary>
''' Spielinformationen
''' </summary>
''' <remarks></remarks>
Public Class GameInfo
    Public CreatorID, MaxPlayers As Integer
    Public GameID As UInteger
    Public Name As String
    Public Version As Version
    Public Flags As GameFlags
    Public PlayerIDs As List(Of Integer)
    Public Password As String
    Public HostAdress As System.Net.IPAddress
    Public CurrentPlayers As Integer
    Enum GameFlags
        Open = 0 'An Open Game for everyone without a Password
        Locked = 1 'Requires a password to enter
        Closed = 2 ' No-one can enter
        InProgress = 4 'The game is currently being played
    End Enum
    Public Sub New(ByVal GameID As UInteger, ByVal CreatorID As Integer, ByVal MaxPlayers As Integer, ByVal Name As String, ByVal Version As Version, ByVal Password As String, ByVal HostAdress As System.Net.IPAddress)
        Me.CreatorID = CreatorID
        Me.MaxPlayers = MaxPlayers
        Me.Name = Name
        Me.Version = Version
        Me.Password = Password
        If Password = "" Then
            Flags = GameFlags.Open
        Else
            Flags = GameFlags.Locked
        End If
        PlayerIDs = New List(Of Integer)
        Me.HostAdress = HostAdress
        Me.GameID = GameID
    End Sub
    Public Sub New(ByVal GameData As String())
        CreatorID = GameData(1)
        MaxPlayers = GameData(2)
        GameID = GameData(3)
        Version = New Version(GameData(4))
        Flags = GameData(5)
        PlayerIDs = New List(Of Integer)
        Dim I As Integer() = ToIntArry(GameData(6).Split("_"))
        For I2 = 0 To I.Length - 1
            PlayerIDs.Add(I(I2))
        Next
        Password = GameData(7)

        If Not System.Net.IPAddress.TryParse(GameData(8), HostAdress) Then
            Dim M As ObjektNetzwerkMenü = Objektverwalter.Menü
            MsgBox("The Lobby wasn't able to get the IP of a new Game! Don't try to play: " + Name + "by " + BaseLobby.FindMember(CreatorID).Username, MsgBoxStyle.Critical, "Getting IP")
        End If

    End Sub
    Public Overrides Function tostring() As String
        Return "Game:" + CreatorID.ToString + ":" + MaxPlayers.ToString + ":" + GameID.ToString + ":" + Name + ":" + Version.ToString + ":" + _
        Flags.ToString + ":" + IntArrayToStr(PlayerIDs.ToArray) + ":" + Password + ":" + HostAdress.ToString


    End Function
    Public Overrides Function Equals(ByVal obj As Object) As Boolean
        If MyBase.Equals(obj) Then
            Return True
        Else
            If TypeOf obj Is GameInfo Then
                Dim G As GameInfo = obj
                If G.Name = Name Then
                    If System.Net.IPAddress.Equals(HostAdress, G.HostAdress) Then
                        Return True
                    End If
                End If
            End If
        End If
    End Function
End Class


''' <summary>
''' Die Lobby
''' </summary>
''' <remarks></remarks>
Public Class BaseLobby
    Enum LobbyModi
        Network
        Online
    End Enum
    Public Shared UpdateTime As Long = TimeSpan.TicksPerSecond * 10
    Dim LastTime As Long
    Public Shared ClientID As Integer = -1
    Public Shared CurrentGame As GameInfo
    Public Shared Games As New List(Of GameInfo)
    Public Shared LobbyMode As LobbyModi = LobbyModi.Network
    Dim Text As ObjektText
    ''' <summary>
    ''' Die User dieser Lobby
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Members As List(Of MemberInfo)
    Public Shared LobbyConnection As Peer
    Public Shared LobbyDeviceAddress As Address
    Public Shared ServerConnected As Boolean = False
    Public Shared ServerHost As Boolean
    Public Shared GameAnswer As Threading.Thread
    Public Breiten(4) As Integer
    Public SearchGames As Boolean = False
    Public Sub New()
        LobbyMode = LobbyModi.Network
        Members = New List(Of MemberInfo)
        Games = New List(Of GameInfo)
        ClientID = -1
        CurrentGame = Nothing
        Text = New ObjektText(New String() {}, 0, 0, Nothing, "Courier New", 16, FontStyle.Regular, False, 3)
        Breiten(0) = Math.DivRem(Hauptmenü.MainMenü.MalPanel.Width - 200, 5, 0)
        Breiten(1) = Breiten(0)
        Breiten(2) = Breiten(0)
        Breiten(3) = Breiten(0)
        Breiten(4) = Breiten(0)

        SearchGames = True
        Dim GetGames As New Threading.Thread(AddressOf FindNetworkGames)
        GetGames.Name = "Commander Wars Network Search Games"
        GetGames.Start()
        LastTime = Now.Ticks
    End Sub
    ''' <summary>
    ''' Creating some Players and Games for a small Test.
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub Test()
        Members.Add(New MemberInfo(0, "Robosturm & Eagle"))
        Members.Add(New MemberInfo(1, "Player 1"))
        Members.Add(New MemberInfo(2, "Player 2"))
        Members.Add(New MemberInfo(3, "Player 3"))
        Members.Add(New MemberInfo(4, "Player 4"))
        Members.Add(New MemberInfo(5, "Player 5"))
        Members.Add(New MemberInfo(6, "Player 7"))
        Members.Add(New MemberInfo(7, "Player 7"))
        Games.Add(New GameInfo(FindNewGameID, 0, 4, "Der Sieger gewinnt", My.Application.Info.Version, "", GetMyIP))
        Games.Add(New GameInfo(FindNewGameID, 6, 4, "Test Spiel 2", My.Application.Info.Version, "", GetMyIP))
        Games.Add(New GameInfo(FindNewGameID, 4, 4, "Test Spiel 3", My.Application.Info.Version, "", GetMyIP))
        Games(1).PlayerIDs.Add(1)
        Games(1).PlayerIDs.Add(2)
        Games(1).PlayerIDs.Add(3)
        CurrentGame = Games(1)
    End Sub
    Public Sub ChangeLobbyMode()
        Select Case LobbyMode
            Case LobbyModi.Online
                LobbyMode = LobbyModi.Network
            Case Else
                If ServerConnected Then
                    LobbyMode = LobbyModi.Online
                Else
                    If My.Settings.LobbyHost Then
                        CreateLobby()
                    Else
                        If My.Settings.LobbyHost Then
                            CreateLobby()
                        Else
                            Dim IP As System.Net.IPAddress = Nothing
                            If Not System.Net.IPAddress.TryParse(My.Settings.LobbyServerIP, IP) Then
                                MsgBox("Unable to create IP Adress of the Lobby Server. This will produce Errors during beeing in the Lobby! Please restart Commander Wars and change the IP to an existing one or create your own Lobby in the Option Menu!", MsgBoxStyle.Critical, "Error while creating Lobby IP")
                            End If
                            BaseLobby.JoinLobby(New Microsoft.DirectX.DirectPlay.Address(IP))
                        End If
                    End If
                End If
        End Select
    End Sub
    ''' <summary>
    ''' Wir erstellen die Lobby als Host
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Sub CreateLobby()
        ServerHost = True
        LobbyConnection = New Peer
        AddHandler LobbyConnection.FindHostResponse, AddressOf BaseLobby.OnFindHost
        AddHandler LobbyConnection.ConnectComplete, AddressOf BaseLobby.OnConnectComplete
        AddHandler LobbyConnection.Receive, AddressOf BaseLobby.NetzBefehlRecieved
        AddHandler LobbyConnection.SessionTerminated, AddressOf BaseLobby.OnSessionTerminated
        'AddHandler NetzConnection.HostMigrated, AddressOf OnHostMigrated
        AddHandler LobbyConnection.PlayerCreated, AddressOf BaseLobby.OnPlayerCreated
        AddHandler LobbyConnection.PlayerDestroyed, AddressOf BaseLobby.OnPlayerDestroyed

        ' Check to see if we can create a TCP/IP connection
        If Not BaseLobby.IsServiceProviderValid(Address.ServiceProviderTcpIp) Then

            ' Nope, can't, quit this application
            MessageBox.Show("Could not create a TCP/IP service provider.", "Exiting", MessageBoxButtons.OK, MessageBoxIcon.Information)
            'Me.Close()
            'Mal schauen, was wir machen müssen wenn wir hier landen, vermutlich auch irgendwie Beenden. Allerdings weiß ich grad nicht genau, wann dieser Fall auftritt.
            Exit Sub
        End If

        ' Erstmal eine Adresse für unsern Computer machen
        LobbyDeviceAddress = New Address()
        LobbyDeviceAddress.ServiceProvider = Address.ServiceProviderTcpIp

        ' Dann brauchen wir noch eine Beschreibung für unser tolles Spiel
        Dim desc As ApplicationDescription = New ApplicationDescription()
        ' desc.Flags += SessionFlags.MigrateHost 'Noch eine Idee meinerseits, ich weiß aber nicht ob das mit den Flags so hinhaut. Auf jeden fall macht die Syntax-Prüfung keinen Error
        'Ist in Commander Wars aber wahrscheinlich auch nicht so wichtig. Da das Spiel vermutlich eh abgebrochen werden muss. Egal, ob Host oder Client das Spiel verlassen.
        'Generell könnte man damit erreichen, dass wenn der Host weg ist, ein Client zum neuen Host ernannt wird, ohne das die Verbindung unterbrochen werden muss.
        desc.SessionName = "Lobby"
        desc.GuidApplication = Hauptmenü.LobbyGUID
        'Eigentlich wird ja automatisch eine GUID erstellt. (My Project -> Assemblyinformationen oder so ähnlich) Aber ich weiß leider nicht, wie wir darauf zugreifen können.
        'So jetzt noch ein paar Sachen in die Desc reinschreiben
        Try 'Host Host Host Host Host Host Host Host Host Host Host Host Host Host Host Host Host Host Host Host Host Host Host Host Host
            LobbyConnection.Host(desc, LobbyDeviceAddress)
            ' Wenn es bis hier keinen Fehler gab, dann hosten wir ein neues Spiel. Glückwunsch :)
            ServerConnected = True 'Also wenn ICH die Session veranstalte, dann bin ich doch wohl verbunden, oder nicht?
        Catch
            ' Console.WriteLine("Netzwerk: Hosting this session has failed. :=(")
        End Try
    End Sub
    ''' <summary>
    ''' Wir treten einer Lobby bei!
    ''' </summary>
    ''' <param name="LobbyAddress"></param>
    ''' <remarks></remarks>
    Public Shared Sub JoinLobby(ByVal LobbyAddress As Address)
        ServerHost = False
        LobbyConnection = New Peer
        AddHandler LobbyConnection.FindHostResponse, AddressOf BaseLobby.OnFindHost
        AddHandler LobbyConnection.ConnectComplete, AddressOf BaseLobby.OnConnectComplete
        AddHandler LobbyConnection.Receive, AddressOf BaseLobby.NetzBefehlRecieved
        AddHandler LobbyConnection.SessionTerminated, AddressOf BaseLobby.OnSessionTerminated
        'AddHandler NetzConnection.HostMigrated, AddressOf OnHostMigrated
        AddHandler LobbyConnection.PlayerCreated, AddressOf BaseLobby.OnPlayerCreated
        AddHandler LobbyConnection.PlayerDestroyed, AddressOf BaseLobby.OnPlayerDestroyed

        ' Check to see if we can create a TCP/IP connection
        If Not BaseLobby.IsServiceProviderValid(Address.ServiceProviderTcpIp) Then

            ' Nope, can't, quit this application
            MessageBox.Show("Could not create a TCP/IP service provider.", "Exiting", MessageBoxButtons.OK, MessageBoxIcon.Information)
            'Me.Close()
            'Mal schauen, was wir machen müssen wenn wir hier landen, vermutlich auch irgendwie Beenden. Allerdings weiß ich grad nicht genau, wann dieser Fall auftritt.
            Exit Sub
        End If

        ' Erstmal eine Adresse für unsern Computer machen
        LobbyDeviceAddress = New Address()
        LobbyDeviceAddress.ServiceProvider = Address.ServiceProviderTcpIp
        ' Dann brauchen wir noch eine Beschreibung für unser tolles Spiel
        Dim desc As ApplicationDescription = New ApplicationDescription()
        ' desc.Flags += SessionFlags.MigrateHost 'Noch eine Idee meinerseits, ich weiß aber nicht ob das mit den Flags so hinhaut. Auf jeden fall macht die Syntax-Prüfung keinen Error
        'Ist in Commander Wars aber wahrscheinlich auch nicht so wichtig. Da das Spiel vermutlich eh abgebrochen werden muss. Egal, ob Host oder Client das Spiel verlassen.
        'Generell könnte man damit erreichen, dass wenn der Host weg ist, ein Client zum neuen Host ernannt wird, ohne das die Verbindung unterbrochen werden muss.
        desc.SessionName = "Lobby"
        desc.GuidApplication = Hauptmenü.LobbyGUID
        'Eigentlich wird ja automatisch eine GUID erstellt. (My Project -> Assemblyinformationen oder so ähnlich) Aber ich weiß leider nicht, wie wir darauf zugreifen können.


        Try 'Client Client Client Client Client Client Client Client Client Client Client Client Client Client Client Client Client Client 
            LobbyConnection.FindHosts(desc, LobbyAddress, LobbyDeviceAddress, Nothing, 0, 0, 0, FindHostsFlags.OkToQueryForAddressing)
            ' Console.WriteLine("Netzwerk: Looking for sessions.") 

        Catch
            '   Console.WriteLine("Netzwerk: Enumeration of sessions has failed.")
        End Try
    End Sub
    ''' <summary>
    ''' Haben wir eine gültige GUID?
    ''' </summary>
    ''' <param name="provider"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function IsServiceProviderValid(ByVal provider As Guid) As Boolean

        ' Ask DirectPlay for the service provider list
        Dim providers() As ServiceProviderInformation = LobbyConnection.GetServiceProviders(True)

        ' For each service provider in the returned list...
        For Each info In providers

            ' Compare the current provider against the passed provider
            If info.Guid = provider Then Return True

        Next

        ' Not found
        Return False
    End Function
    ''' <summary>
    ''' Wir haben einen Host gefunden!
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Public Shared Sub OnFindHost(ByVal sender As Object, ByVal e As Microsoft.DirectX.DirectPlay.FindHostResponseEventArgs)
        SyncLock LobbyConnection 'Da wir ja nicht wollen, dass 2 Threads gleichzeitig zwei unterschiedliche Hosts finden und dann diese Routine zwei mal durchlaufen wird. Ich glaube du verstehst was ich meine und ja, die Wahrscheinlichkeit ist gar nicht mal so niedrig!
            'ein bischen abgewandelt. Ursprünglich:      SyncLock Me

            If ServerConnected Then Exit Sub 'Wenn wir schon verbunden sind, brauchen wir keine neue Verbindung mehr.

            ServerConnected = True 'Ab jetzt sind wir verbunden
            Dim foundSession As String = String.Format("Found session ({0}), trying to connect.", e.Message.ApplicationDescription.SessionName)



            'erstmal ein kleines Begrüßungsgeschenk machen :) (Dein Nickname)
            Dim Geschenk As New NetworkPacket
            Geschenk.Write(My.Settings.Autor) 'Allerdings weiß ich nicht wie man das "Geschenk" erhält :[
            'Mit dem erstbesten verbinden
            Dim pee As Peer = sender
            pee.Connect(e.Message.ApplicationDescription, e.Message.AddressSender, e.Message.AddressDevice, Geschenk, Microsoft.DirectX.DirectPlay.ConnectFlags.OkToQueryForAddressing)
        End SyncLock 'Ende SyncLock. Der Kritische Breich, in dem nur ein Thread gleichzeitig arbeiten kann ist vorbei. Puh!

        'Noch ne Anmerkung:
        'Was das "OkToQueryForAddressing" Flag betrifft. (Es geht natürlich auch ohne). Das heißt, das DirectPlay seine eigenen Fensterchen machen darf. Bei dem beitreten kommt ja nochmal ein Fensterchen, wo man den Hostnamen eingeben soll... Wenn man den Flag nicht setzt (In einem VollBild-Spiel wäre das ja doof) werden dann halt Exceptions geworfen. stell also sicher das Hostname, Port und so weiter angegeben ist!
    End Sub
    ''' <summary>
    ''' Wir haben die Verbindung aufgebaut!
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Public Shared Sub OnConnectComplete(ByVal sender As Object, ByVal e As Microsoft.DirectX.DirectPlay.ConnectCompleteEventArgs)
        ' Nachschauen, ob wir korrekt verbunden sind.
        If e.Message.ResultCode = Microsoft.DirectX.DirectPlay.ResultCode.Success Then
            'Console.WriteLine("Netzwerk: Connect Success.")
            ServerConnected = True
            'Wir sind verbunden! Dann mal los!
            SyncLock Members
                ClientID = e.Message.LocalPlayerId
                Dim M As MemberInfo = FindMember(ClientID)
                M.Username = My.Settings.Autor
                M.Flags = MemberInfo.MemberFlag.Lobby
            End SyncLock
        Else
            ' Console.WriteLine("Netzwerk: Connect Failure: " + e.Message.ResultCode.ToString)
            ServerConnected = False
        End If

        'SyncLock NetzTeilnehmer
        '    Array.Resize(NetzTeilnehmer, NetzConnection.Players.Count)
        '    For i = 0 To NetzTeilnehmer.Length - 1
        '        Dim s As String = NetzConnection.Players.Item(i).ToString
        '        Dim nT As New NetzwerkTeilnehmer(CInt(s))
        '        NetzTeilnehmer(i) = nT
        '    Next
        'End SyncLock
    End Sub
    ''' <summary>
    ''' Die Sitzung wurde von jemanden beendet dann raus mit ihm!
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Public Shared Sub OnSessionTerminated(ByVal sender As Object, ByVal e As Microsoft.DirectX.DirectPlay.SessionTerminatedEventArgs)
        ServerConnected = False
    End Sub
    ''' <summary>
    ''' Ein Spieler wurde erschaffen!
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Public Shared Sub OnPlayerCreated(ByVal sender As Object, ByVal e As Microsoft.DirectX.DirectPlay.PlayerCreatedEventArgs)
        Dim nT As New MemberInfo(e.Message.PlayerID)

        SyncLock Members
            If Members.Count = 0 Then
                ClientID = e.Message.PlayerID
            End If
            Members.Add(nT)
            'Es gibt einen neuen Spieler. Dann teilen wir ihm am besten unseren Nickname mit, damit wir uns schön unterhalten können :)
            Dim M As MemberInfo = FindMember(ClientID)
            If M IsNot Nothing Then
                NetzBefehlSenden("NewMember:" + M.ID.ToString + ":" + M.Username)
            End If
        End SyncLock

    End Sub
    ''' <summary>
    ''' Ein Spieler wurde zerstört! o.O
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Public Shared Sub OnPlayerDestroyed(ByVal sender As Object, ByVal e As Microsoft.DirectX.DirectPlay.PlayerDestroyedEventArgs)
        If Members IsNot Nothing Then
            SyncLock Members
                If LobbyConnection.Disposed Then Exit Sub 'Wir scheinen die Verbindung ordnungsgemäß beendet zu haben.

                Dim i As Integer = 0
                If ServerConnected Then
                    Do Until i > LobbyConnection.Players.Count
                        If Members(i).ID = e.Message.PlayerID Then
                            Members.RemoveAt(i)
                            Exit Sub
                        End If
                    Loop
                End If
            End SyncLock
        End If
    End Sub
    ''' <summary>
    ''' Wir verlassen die Lobby!
    ''' </summary>
    ''' <param name="Text"></param>
    ''' <remarks></remarks>
    Public Shared Sub NetzLeaveGame(ByVal Text As String)
        Dim Begründung As New NetworkPacket
        Begründung.Write(Text)
        LobbyConnection.TerminateSession(Begründung)
        LobbyConnection.Dispose()
    End Sub
    ''' <summary>
    ''' Wir haben ein paar Daten empfangen!
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Public Shared Sub NetzBefehlRecieved(ByVal sender As Object, ByVal e As Microsoft.DirectX.DirectPlay.ReceiveEventArgs)
        Dim Paket As NetworkPacket = e.Message.ReceiveData 'Das Paket empfangen
        Dim Nachricht As String() = Paket.ReadString.Split(":")
        Select Case Nachricht(0).ToLower
            Case "spielstart" 'Da haben woll ein paar ein Spiel gestartet!
                Dim ID As Integer = Nachricht(1)
                SyncLock Games
                    For I = 0 To Games.Count - 1
                        If Games(I).GameID = ID Then
                            Games.RemoveAt(I)
                            Exit For
                        End If
                    Next
                End SyncLock
            Case "newmember" 'Ein neuer Spieler ist da!
                SyncLock Members
                    Dim M As MemberInfo = FindMember(Nachricht(1))
                    M.Username = Nachricht(2)
                    M.Flags = MemberInfo.MemberFlag.Lobby
                End SyncLock
            Case "gamecreated"
                If ServerHost Then 'Zwar nicht Ideal aber egal!
                    'jetzt senden wir das neue Spiel an alle
                    Dim G As New GameInfo(Nachricht)
                    SyncLock Games
                        G.GameID = FindNewGameID()
                        Games.Add(G)
                    End SyncLock
                    NetzBefehlSenden("NewGame:" + G.tostring)
                End If
            Case "newgame" 'Ein neues Spiel wurde erstellt!
                SyncLock Games
                    Games.Add(New GameInfo(Nachricht))
                End SyncLock
            Case "getgames"

        End Select
    End Sub
    ''' <summary>
    ''' Wir wollen ein paar Daten senden!
    ''' </summary>
    ''' <param name="Daten"></param>
    ''' <remarks></remarks>
    Public Shared Sub NetzBefehlSenden(ByVal Daten As String)
        If Not ServerConnected Then Exit Sub
        Dim Paket As New NetworkPacket
        Paket.Write(Daten)
        LobbyConnection.SendTo(PlayerID.AllPlayers, Paket, 0, 40)
    End Sub

    ''' <summary>
    ''' Überprüft ob die Versionen gleich sind.
    ''' </summary>
    ''' <param name="V1"></param>
    ''' <param name="V2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function VersionMatch(ByVal V1 As Version, ByVal V2 As Version) As Boolean
        If V1 = V2 Then
            Return True
        Else
            Return False
        End If
    End Function
    ''' <summary>
    ''' Wir starten ein Spiel also verlassen wir die Lobby!
    ''' Damit wir eine überlastung vermeiden!
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub StartGame(ByVal GameID As UInteger)
        SyncLock Games
            For I = 0 To Games.Count - 1
                If Games(I).GameID = GameID Then
                    Games(I).Flags = GameInfo.GameFlags.InProgress
                    If Not ServerHost Then
                        NetzLeaveGame("SpielStart:" + Games(I).Name)
                    End If
                    Games.RemoveAt(I)
                    Exit For
                End If
            Next
        End SyncLock
    End Sub
    ''' <summary>
    ''' Wir treten einem Spiel bei!
    ''' </summary>
    ''' <param name="GameID"></param>
    ''' <param name="Password"></param>
    ''' <remarks></remarks>
    Public Sub JoinGame(ByVal GameID As UInteger, ByVal Password As String)
        For Each Game In Games
            If Game.GameID = GameID Then 'Das ist das Spiel zu dem wir beitreten werden!
                If VersionMatch(Game.Version, My.Application.Info.Version) Then
                    If Game.Flags = GameInfo.GameFlags.Locked Then
                        If Password = Game.Password Then 'Richtiges Passwort?
                            If Game.PlayerIDs.Count + 1 < Game.MaxPlayers Then 'Kann noch einer Mitspielen?
                                Game.PlayerIDs.Add(ClientID)
                                Hauptmenü.NetzIni(New Address(Game.HostAdress))
                                FindMember(ClientID).Flags = MemberInfo.MemberFlag.Joined
                                CurrentGame = Game
                            End If
                        End If
                    ElseIf Game.Flags = GameInfo.GameFlags.Open Then
                        If Game.PlayerIDs.Count + 1 < Game.MaxPlayers Then 'Kann noch einer Mitspielen?
                            Game.PlayerIDs.Add(ClientID)
                            Hauptmenü.NetzIni(New Address(Game.HostAdress))
                            FindMember(ClientID).Flags = MemberInfo.MemberFlag.Joined
                            CurrentGame = Game
                        End If
                    End If
                End If
            End If
        Next
    End Sub
    ''' <summary>
    ''' Wir suchen einen bestimmten Teilnehmer
    ''' </summary>
    ''' <param name="MemberID"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function FindMember(ByVal MemberID As Integer) As MemberInfo
        For Each Member In Members
            If Member.ID = MemberID Then
                Return Member
            End If
        Next
        Return Nothing
    End Function
    ''' <summary>
    ''' Wir suchen ein bestimmtes Spiel!
    ''' </summary>
    ''' <param name="GameID"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function FindGame(ByVal GameID As UInteger) As GameInfo
        For Each Game In Games
            If Game.GameID = GameID Then
                Return Game
            End If
        Next
        Return Nothing
    End Function

    Public Shared Function FindNewGameID() As UInteger
        Dim NewID As UInteger = 0
        SyncLock Games

            While ExistsGameID(NewID)
                NewID += 1
            End While
        End SyncLock
        Return NewID
    End Function
    Public Shared Function FindNewMemberID() As Integer
        Dim NewID As Integer = Integer.MinValue
        SyncLock Members
            While ExistsGameID(NewID)
                NewID += 1
            End While
        End SyncLock
        Return NewID
    End Function
    Public Shared Function ExistsGameID(ByVal GameID As UInteger) As Boolean
        For Each Game In Games
            If Game.GameID = GameID Then
                Return True
            End If
        Next
        Return False
    End Function
    Public Shared Function GetMyIP() As System.Net.IPAddress
        Dim h As System.Net.IPHostEntry = System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName)
        Return h.AddressList(0)
    End Function
    ''' <summary>
    ''' Wir verlassen die Lobby und beenden sie!
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub ExitLobby()
        ListenForAnswers = False
        If ServerConnected Then
            If LobbyConnection.Disposed = False Then
                NetzLeaveGame("Lobby Verlassen")
                LobbyConnection.Dispose()
            End If
            If LobbyDeviceAddress.Disposed = False Then
                LobbyDeviceAddress.Dispose()
            End If
            ServerConnected = False
            ServerHost = False
        End If
    End Sub
    
    ''' <summary>
    ''' Malt die Ganze Lobby
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub Malen()
        Dim sngrotation As Single = 0
        Dim intColor As Color = Color.FromArgb(255, 255, 255, 255)
        Dim BuchstabenDimension As Size = Text.GetSchriftart.MeasureString(Schriftengine.Sprite2, "A", DrawTextFormat.None, Color.Black).Size
        Dim Höhe As Integer = Hauptmenü.MainMenü.MalPanel.Height - 300
        Dim B As Integer = 0
        'So das Grundgerüst malen!
        For I = 0 To 4
            B = 0
            For I2 = 0 To I - 1
                B += Breiten(I2)
            Next
            Grafikengine.DrawBox(New Rectangle(100 + B, 100, Breiten(I), Höhe), Color.Black, 2)
        Next
        'Obere Zeile
        For I = 0 To Games.Count
            Grafikengine.DrawBox(New Rectangle(100, 100 + I * (BuchstabenDimension.Height + 4), Hauptmenü.MainMenü.MalPanel.Width - 200, BuchstabenDimension.Height + 4), Color.Black, 2)
        Next
        If CurrentGame IsNot Nothing Then
            For I = 0 To Games.Count - 1
                If Games(I).GameID = CurrentGame.GameID Then
                    Grafikengine.DrawBox(New Rectangle(100, 100 + (I + 1) * (BuchstabenDimension.Height + 4), Hauptmenü.MainMenü.MalPanel.Width - 200, BuchstabenDimension.Height + 4), Color.Blue, 2)
                End If
            Next
        End If
        Grafikengine.Sprite.End()
        Schriftengine.Sprite2.Begin(SpriteFlags.AlphaBlend)
        Dim Spielname(0) As String
        Spielname(0) = ShortenWort(Sprachconverter.Translate("Host"), Breiten(0) - 4, BuchstabenDimension.Width)
        Text.neuerText(Spielname, 100 + Breiten(0) / 2 - Spielname(0).Length / 2 * BuchstabenDimension.Width, 102, Nothing, , 4)
        Text.Malen(Schriftengine.Sprite2)
        B = Breiten(0)
        Spielname(0) = ShortenWort(Sprachconverter.Translate("Spielname"), Breiten(1) - 4, BuchstabenDimension.Width)
        Text.neuerText(Spielname, 100 + B + Breiten(1) / 2 - Spielname(0).Length / 2 * BuchstabenDimension.Width, 102, Nothing, , 4)
        Text.Malen(Schriftengine.Sprite2)
        B += Breiten(1)
        Spielname(0) = ShortenWort(Sprachconverter.Translate("Spielerzahl"), Breiten(2) - 4, BuchstabenDimension.Width)
        Text.neuerText(Spielname, 100 + B + Breiten(2) / 2 - Spielname(0).Length / 2 * BuchstabenDimension.Width, 102, Nothing, , 4)
        Text.Malen(Schriftengine.Sprite2)
        B += Breiten(2)
        Spielname(0) = ShortenWort(Sprachconverter.Translate("Version"), Breiten(3) - 4, BuchstabenDimension.Width)
        Text.neuerText(Spielname, 100 + B + Breiten(3) / 2 - Spielname(0).Length / 2 * BuchstabenDimension.Width, 102, Nothing, , 4)
        Text.Malen(Schriftengine.Sprite2)
        B += Breiten(3)
        Spielname(0) = ShortenWort(Sprachconverter.Translate("Passwort"), Breiten(4) - 4, BuchstabenDimension.Width)
        Text.neuerText(Spielname, 100 + B + Breiten(4) / 2 - Spielname(0).Length / 2 * BuchstabenDimension.Width, 102, Nothing, , 4)
        Text.Malen(Schriftengine.Sprite2)
        ReDim Spielname(Games.Count - 1)
        For I = 0 To Games.Count - 1
            Spielname(I) = ShortenWort(FindMember(Games(I).CreatorID).Username, Breiten(0) - 4, BuchstabenDimension.Width)
        Next
        Text.neuerText(Spielname, 104, 102 + BuchstabenDimension.Height + 4, Nothing, , 4)
        Text.Malen(Schriftengine.Sprite2)
        For I = 0 To Games.Count - 1
            Spielname(I) = ShortenWort(Games(I).Name, Breiten(1) - 4, BuchstabenDimension.Width)
        Next
        B = Breiten(0)
        Text.neuerText(Spielname, 104 + B, 102 + BuchstabenDimension.Height + 4, Nothing, , 4)
        Text.Malen(Schriftengine.Sprite2)
        For I = 0 To Games.Count - 1
            Spielname(I) = ShortenWort((Games(I).PlayerIDs.Count + 1).ToString + "/" + Games(I).MaxPlayers.ToString, Breiten(2) - 4, BuchstabenDimension.Width)
        Next
        B += Breiten(1)
        Text.neuerText(Spielname, 104 + B, 102 + BuchstabenDimension.Height + 4, Nothing, , 4)
        Text.Malen(Schriftengine.Sprite2)
        For I = 0 To Games.Count - 1
            Spielname(I) = ShortenWort(Games(I).Version.ToString, Breiten(3) - 4, BuchstabenDimension.Width)
        Next
        B += Breiten(2)
        Text.neuerText(Spielname, 104 + B, 102 + BuchstabenDimension.Height + 4, Nothing, , 4)
        Text.Malen(Schriftengine.Sprite2)
        For I = 0 To Games.Count - 1
            Spielname(I) = ShortenWort(Games(I).Flags.ToString, Breiten(4) - 4, BuchstabenDimension.Width)
        Next
        B += Breiten(3)
        Text.neuerText(Spielname, 104 + B, 102 + BuchstabenDimension.Height + 4, Nothing, , 4)
        Text.Malen(Schriftengine.Sprite2)
        Schriftengine.Sprite2.End()
        Grafikengine.Sprite.Begin(SpriteFlags.AlphaBlend)

        Dim T As Long = Now.Ticks
        If Not SearchGames Then
            If T - LastTime >= UpdateTime Then
                SearchGames = True
                Dim GetGames As New Threading.Thread(AddressOf FindNetworkGames)
                GetGames.Name = "Commander Wars Network Search Games"
                GetGames.Start()
                LastTime = T
            End If
        End If
    End Sub
    Private Function ShortenWort(ByVal Wort As String, ByVal Breite As Integer, ByVal Buchstabenbreite As Integer) As String
        Dim Buchstabenzahl As Integer = Math.DivRem(Breite, Buchstabenbreite, 0)
        Dim Rückgabe As String = ""
        If Wort.Length > Buchstabenzahl Then
            Rückgabe = Wort.Substring(0, Buchstabenzahl - 3) + "..."
        Else
            Rückgabe = Wort
        End If
        Return Rückgabe
    End Function
    Public Function MouseDown(ByVal e As System.Windows.Forms.MouseEventArgs) As Boolean
        Select Case e.Button
            Case MouseButtons.Right
                CurrentGame = Nothing
            Case MouseButtons.Left
                Dim B As Integer = Breiten(0) + Breiten(1) + Breiten(2) + Breiten(3) + Breiten(4)
                Dim H As Integer = Text.GetSchriftart.MeasureString(Schriftengine.Sprite2, "A", DrawTextFormat.None, Color.Black).Height
                For I = 0 To Games.Count - 1
                    If New Rectangle(100, 100 + (I + 1) * (H + 4), B, H).Contains(e.Location) Then
                        CurrentGame = Games(I)
                        Return False
                    End If
                Next
                If e.Clicks > 1 Then

                End If
        End Select

        Return True
    End Function

#Region "Search Network Games"
    Dim Code As System.Text.Encoding = System.Text.Encoding.UTF8
    Const portNumber As Integer = 8000
    Public Shared ListenForAnswers As Boolean = True

    ''' <summary>
    ''' Hier sollten die Spiele gesucht werden die im Netzwerk zu finden sind.
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub FindNetworkGames()

        Shell(My.Settings.Resourcenpfad + "Network\getOthers.bat", AppWinStyle.Hide, True)
        Dim Netzteilnehmer As New Stack(Of String)
        Using StrR As New IO.StreamReader("others.txt")
            While Not StrR.EndOfStream
                Dim Z As String = StrR.ReadLine.Trim
                If Z.StartsWith("\\") Then
                    Dim NT As String = Z.Remove(0, 2).Trim.ToUpper.Split(" ")(0)
                    If NT <> System.Net.Dns.GetHostName.ToUpper Then
                        Netzteilnehmer.Push(NT)
                    End If
                End If
            End While
        End Using
        My.Computer.FileSystem.DeleteFile("others.txt")
        Dim NewGames As New List(Of GameInfo)
        Dim NewMembers As New List(Of MemberInfo)
        While Netzteilnehmer.Count > 0
            Dim Game As String = uClientMeldungMachen("Get Game", Netzteilnehmer.Pop)
            If Game.StartsWith("Game_") Then
                Dim GInfo As String() = Game.Split("_")
                NewGames.Add(New GameInfo(GInfo(3).Split(":")))
                NewGames(NewGames.Count - 1).MaxPlayers = GInfo(2)
                NewMembers.Add(New MemberInfo(FindNewMemberID, GInfo(1), MemberInfo.MemberFlag.Joined))
            End If
        End While
        If CurrentGame IsNot Nothing Then
            SyncLock CurrentGame
                SyncLock Members
                    SyncLock Games
                        If CurrentGame IsNot Nothing Then
                            For Each G In NewGames
                                If G.Equals(CurrentGame) Then
                                    CurrentGame = G
                                    Exit For
                                End If
                            Next
                        End If
                        Members = NewMembers
                        Games = NewGames
                    End SyncLock
                End SyncLock
            End SyncLock
        Else
            SyncLock Members
                SyncLock Games
                    If CurrentGame IsNot Nothing Then
                        For Each G In NewGames
                            If G.Equals(CurrentGame) Then
                                CurrentGame = G
                                Exit For
                            End If
                        Next
                    End If
                    Members = NewMembers
                    Games = NewGames
                End SyncLock
            End SyncLock
        End If
        SearchGames = False
    End Sub


    Public Sub GameStarted()
        Dim T As New Threading.Thread(AddressOf uRoutineHost)
        T.Name = "Commander Wars Game Info"
        ListenForAnswers = True
        T.Start()
    End Sub

    Private Sub uRoutineHost()

        ' Must listen on correct port- must be same as port client wants to connect on.



        Dim tcpListener As New TcpListener(GetMyIP, portNumber)
        Dim M As ObjektNetzwerkMenü = Objektverwalter.Menü
        tcpListener.Start()

        If M.KAModus = ObjektKartenauswahlMenü.KAModi.SpielerAuswahl Then
            While ListenForAnswers = True

                ' Console.WriteLine("Waiting for connection...")

                Try

                    'Accept the pending client connection and return a TcpClient initialized for communication.

                    Dim tcpClient As TcpClient = tcpListener.AcceptTcpClient()

                    ' Console.WriteLine("Connection accepted.")

                    ' Get the stream

                    Dim networkStream As NetworkStream = tcpClient.GetStream()

                    ' Read the stream into a byte array

                    Dim bytes(tcpClient.ReceiveBufferSize) As Byte

                    networkStream.Read(bytes, 0, CInt(tcpClient.ReceiveBufferSize))

                    ' Return the data received from the client to the console.

                    Dim clientdata As String = Code.GetString(bytes)


                    'clientdata ist der String, der der Client geschickt hat, der wird jetzt in Meldung auf dem Bildschirm angezeigt.


                    If clientdata = "Get Game" Then
                        Dim S As ObjektSpielfeld = M.SpielKarten(ObjektKartenauswahlMenü.AngezeigteKarten(ObjektKartenauswahlMenü.MomentaneKarte))
                        Dim G As New GameInfo(0, BaseLobby.ClientID, S.Spieler.Length - 1, S.Kartenname, My.Application.Info.Version, "", BaseLobby.GetMyIP)
                        Dim CurrentPlayers As Integer = 0
                        For I = 0 To M.KIStufen.Length - 1
                            If M.KIStufen(0) <> ObjektSpieler.KIStufen.Offen Then
                                CurrentPlayers += 1
                            End If
                        Next

                        Dim responseString As String = "Game_" + My.Settings.Autor + "_" + CurrentPlayers + "_" + G.tostring
                        '"Connected to server."



                        Dim sendBytes As [Byte]() = Code.GetBytes(responseString)

                        networkStream.Write(sendBytes, 0, sendBytes.Length)

                        'Console.WriteLine(("Message Sent /> : " + responseString))

                        'Any communication with the remote client using the TcpClient can go here.

                        'Close TcpListener and TcpClient.

                        tcpClient.Close()
                    End If
                Catch e As Exception

                    Console.WriteLine(e.ToString())

                End Try

            End While
        End If
        tcpListener.Stop()
        ListenForAnswers = False

    End Sub

    Private Function uClientMeldungMachen(ByVal Nachricht As String, ByVal HostIP As String) As String

        Dim b As Boolean = My.Computer.Network.Ping(HostIP, 500)

        If b = True Then

            'MsgBox("Der Angegebene Zielcomputer wurde erreicht!", MsgBoxStyle.Information, "Erfolg!")
            Try
                Dim tcpClient As New System.Net.Sockets.TcpClient()

                tcpClient.Connect(HostIP, portNumber)

                Dim networkStream As NetworkStream = tcpClient.GetStream()

                If networkStream.CanWrite And networkStream.CanRead Then

                    ' Do a simple write.

                    Dim sendBytes As [Byte]()

                    sendBytes = Code.GetBytes(Nachricht) '("Is anybody there")

                    networkStream.Write(sendBytes, 0, sendBytes.Length)

                    ' Read the NetworkStream into a byte buffer.

                    Dim bytes(tcpClient.ReceiveBufferSize) As Byte

                    networkStream.Read(bytes, 0, CInt(tcpClient.ReceiveBufferSize))

                    ' Output the data received from the host to the console.

                    networkStream.Close()

                    Return Code.GetString(bytes)

                Else

                    If Not networkStream.CanRead Then

                        Console.WriteLine("cannot not write data to this stream")

                        tcpClient.Close()

                    Else

                        If Not networkStream.CanWrite Then

                            Console.WriteLine("cannot read data from this stream")

                            tcpClient.Close()

                        End If



                    End If
                    networkStream.Close()
                End If

                ' pause so user can view the console output
            Catch

                Console.WriteLine("Couldn't connect to Computer, that was found! Computer IP\Name:" + HostIP + ".")

            End Try
        Else

            Console.WriteLine("Couldn't connect to Computer, that was found! Computer IP\Name:" + HostIP + ".")

        End If

        Return ""
    End Function

#End Region
End Class



